package keycloak

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"
)

type KeyCLoakInfo struct {
	Url          string `yaml:"keycloak_url"`
	Realm        string `yaml:"realm"`
	Clientid     string `yaml:"client_id"`
	Clientsecret string `yaml:"client_secret"`
	RedirectUri  string `yaml:"redirect_uri"`
}

func NewKeyCloakFrominter(any interface{}) *KeyCLoakInfo {
	con := any.(map[string]interface{})
	return &KeyCLoakInfo{
		Url:          con["keycloak_url"].(string),
		Realm:        con["realm"].(string),
		Clientid:     con["client_id"].(string),
		Clientsecret: con["client_secret"].(string),
		RedirectUri:  con["redirect_uri"].(string),
	}
}

func (kcm *KeyCLoakInfo) AuthCheck(username string, password string) error {
	posturl, _ := url.JoinPath(kcm.Url, "realms", kcm.Realm, "protocol/openid-connect/token")
	datapro := make(url.Values)
	datapro.Add("grant_type", "password")
	datapro.Add("client_id", kcm.Clientid)
	datapro.Add("client_secret", kcm.Clientsecret)
	datapro.Add("username", username)
	datapro.Add("password", password)
	fmt.Println(posturl)
	req, _ := http.NewRequest("POST", posturl, strings.NewReader(datapro.Encode()))
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	client := &http.Client{}
	if resp, er := client.Do(req); er != nil {
		return er
	} else {
		if resp.StatusCode == 200 {
			return nil
		}
		return errors.New("invad username/password")
	}
}
func (kcm *KeyCLoakInfo) gettokenbycode(code string) (string, error) {
	posturl, _ := url.JoinPath(kcm.Url, "realms", kcm.Realm, "protocol/openid-connect/token")
	datapro := make(url.Values)
	datapro.Add("grant_type", "authorization_code")
	datapro.Add("client_id", kcm.Clientid)
	datapro.Add("client_secret", kcm.Clientsecret)
	datapro.Add("redirect_uri", kcm.RedirectUri)
	datapro.Add("code", code)
	req, _ := http.NewRequest("POST", posturl, strings.NewReader(datapro.Encode()))
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	client := &http.Client{}
	if resp, er := client.Do(req); er != nil {
		return "", er
	} else {
		if resp.StatusCode == 200 {
			data, _ := io.ReadAll(resp.Body)
			values := map[string]interface{}{}
			er = json.Unmarshal(data, &values)
			if er != nil {
				return "", er
			}
			fmt.Println(values)
			if strinterface, ok := values["access_token"]; ok {
				return strinterface.(string), nil
			} else {
				return "", errors.New("access_token can't get")
			}

		}
		return "", errors.New("response error")
	}
}

// 使用code 返回username
func (kcm *KeyCLoakInfo) AuthCheckCode(code string) (string, error) {
	token, er := kcm.gettokenbycode(code)
	if er != nil {
		return "", er
	}
	posturl, _ := url.JoinPath(kcm.Url, "realms", kcm.Realm, "protocol/openid-connect/userinfo")

	req, _ := http.NewRequest("POST", posturl, nil)
	req.Header.Add("Authorization", "Bearer "+token)
	client := &http.Client{}
	if resp, er := client.Do(req); er != nil {
		return "", er
	} else {
		if resp.StatusCode == 200 {
			data, _ := io.ReadAll(resp.Body)
			values := map[string]interface{}{}
			er = json.Unmarshal(data, &values)
			if er != nil {
				return "", er
			}
			if strinterface, ok := values["preferred_username"]; ok {
				return strinterface.(string), nil
			} else {
				return "", errors.New("preferred_username can't get")
			}

		}
		return "", errors.New("response error")
	}

}

var KeyCloakMangerClient *KeyCLoakInfo

/*
realm: gcloud
client_id: videoauto
client_secret: 2c518353-7346-421f-aee0-a6414a1b8607
keycloak_url: https://gcloud-auth.geniusafc.com/api/v1
redirect_uri: https://10.33.130.88/login
*/
func SetKeyCloak(config interface{}) {
	KeyCloakMangerClient = NewKeyCloakFrominter(config)
}
